import time, os, sqlite3
from threading import Thread
import numpy as np
import pandas as pd
from tqsdk import TqApi, TqAuth, TqKq
from rich.console import Console
from rich.theme import Theme
from MyTT import REF, EMA, SUM
import logging

# 配置日志记录
logging.basicConfig(
    filename='trading_log.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# 改变控制台背景色和字体色，控制台窗口大小
os.system("COLOR 02")
os.system("mode con cols=150 lines=50")

# 定义颜色主题
# 定义更明亮显眼的颜色主题
custom_theme = Theme({
    "info": "bright_cyan",
    "warning": "bright_yellow",
    "error": "bright_red",
    "success": "bright_green",
    "trade": "bold bright_magenta"
})
console = Console(theme=custom_theme)

# 定义全局变量
symbols = []
api = None
threads = []


# 新增函数：获取 config 表所有配置项
def get_all_configs():
    """
    从 config 表中获取所有配置项，以字典形式返回
    :return: 包含所有配置项的字典
    """
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT key, value FROM config")
        results = cursor.fetchall()
        conn.close()
        return dict(results)
    except Exception as e:
        console.print(f"从数据库获取所有配置项时出错: {e}", style="error")
        return {}

def get_symbols():
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        # 查询品种代码和 mtp 字段
        cursor.execute("SELECT exchange_code FROM products WHERE is_monitored=1")
        products = cursor.fetchall()
        conn.close()
        # 返回包含品种代码和 mtp 值的列表
        return [product[0] for product in products]
    except Exception as e:
        console.print(f"从数据库获取监控品种时出错: {e}", style="error")
        return []

def stop_loss(symbol):
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT limit_stoploss,mtp,dks FROM products WHERE exchange_code=? AND is_monitored=1", (symbol,))
        result = cursor.fetchone()
        conn.close()
        if result is None:
            stop_loss_limit = 3000  # 限额止损
            mtp = 5  # 移动止盈止损周期
            dks = "双向"  # 开仓方向
        else:
            stop_loss_limit = int(result[0])  # 限额止损
            # 处理 mtp 数据，确保其为有效的整数
            try:
                mtp = int(result[1])
                # 限制 mtp 在合理范围内，例如 1 到 3600
                mtp = max(1, min(mtp, 3600))
            except (ValueError, TypeError):
                console.print(f"从数据库获取 {symbol} 的 mtp 值无效，使用默认值", style="warning")
                mtp = 5
            dks = str(result[2])  # 开仓方向
    except Exception as e:
        console.print(f"从数据库获取 {symbol} 止损限额时出错: {e}", style="error")
        return
    console.print(f"{time.strftime('%X')} 开始检查{symbol}止损条件", style="warning")
    klines = api.get_kline_serial(symbol, 60 * mtp, data_length=300)
    quote = api.get_quote(symbol)
    position = api.get_position(symbol)
    orders = api.get_order(symbol)

    console.print(f"{time.strftime('%X')} 开始处理 {symbol}", style="warning")
    if True:
        console.print(f"{time.strftime('%X')} 数据更新", style="info")
        try:
            # 撤销所有未成交订单
            for order in orders.items():
                if hasattr(order, 'status') and order.status == 'ALIVE':
                    api.cancel_order(order)

            # ***************************************限额止损检查***************************************
            if position.pos_short > 0:
                short_loss_per_hand = (position.open_price_short - quote.last_price) * quote.volume_multiple 
                if short_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        if position.pos_short_today > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            volume = position.pos_short_today
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="BUY",
                                    offset="CLOSETODAY",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平SHFE{symbol}今空仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平SHFE{symbol}今空仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )
                        if position.pos_short_his > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            volume = position.pos_short_his
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="CLOSE",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平SHFE{symbol}昨空仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平SHFE{symbol}昨空仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )
                    else:
                        # 非上海交易所空单限额止损                        
                        if position.pos_short > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            volume = position.pos_short
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="CLOSE",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平{symbol}空仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平{symbol}空仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )


            if position.pos_long > 0:
                long_loss_per_hand = (quote.last_price - position.open_price_long) * quote.volume_multiple 
                if long_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        if position.pos_long_today > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            volume = position.pos_long_today
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="SELL",
                                    offset="CLOSETODAY",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平SHFE{symbol}今多仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平SHFE{symbol}今多仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )
                        if position.pos_long_his > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            volume = position.pos_long_his
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="SELL",
                                    offset="CLOSE",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平SHFE{symbol}昨多仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平SHFE{symbol}昨多仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )
                    else:
                        if position.pos_long > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            volume = position.pos_long
                            if volume > 0:
                                api.insert_order(
                                    symbol=symbol,
                                    direction="SELL",
                                    offset="CLOSE",
                                    volume=volume,
                                    limit_price=limit_price
                                )
                                console.print(
                                    f"{time.strftime('%X')} 平{symbol}多仓(限额止损): 手数: {volume}",
                                    style="trade"
                                )
                                # 仅保留下单信息日志
                                logging.info(
                                    f"平{symbol}多仓(限额止损): 手数: {volume}, 平仓价格: {limit_price}"
                                )

            # ***************************************趋势追踪止损检查***************************************
            close = klines.close
            low = klines.low
            open = klines.open
            high = klines.high
            close = np.array(close)
            low = np.array(low)
            open = np.array(open)
            high = np.array(high)

            Q = (3 * close + low + open + high) / 6
            terms = [
                26 * Q,
                25 * REF(Q, 1),
                24 * REF(Q, 2),
                23 * REF(Q, 3),
                22 * REF(Q, 4),
                21 * REF(Q, 5),
                20 * REF(Q, 6),
                19 * REF(Q, 7),
                18 * REF(Q, 8),
                17 * REF(Q, 9),
                16 * REF(Q, 10),
                15 * REF(Q, 11),
                14 * REF(Q, 12),
                13 * REF(Q, 13),
                12 * REF(Q, 14),
                11 * REF(Q, 15),
                10 * REF(Q, 16),
                9 * REF(Q, 17),
                8 * REF(Q, 18),
                7 * REF(Q, 19),
                6 * REF(Q, 20),
                5 * REF(Q, 21),
                4 * REF(Q, 22),
                3 * REF(Q, 23),
                2 * REF(Q, 24),
                REF(Q, 25)
            ]
            trading_line = sum(terms) / 351
            short_line = EMA(trading_line, 7)
           #logging.info(f"Symbol: {symbol}, Trading Line[-2]: {trading_line[-2]}, Short Line[-2]: {short_line[-2]}")
            console.print(f"条件值是： {trading_line[-2]}, {short_line[-2]}",style="trade")

            if len(trading_line) >= 2 and len(short_line) >= 2:
                # 处理空单
                if  trading_line[-2] > short_line[-2]:
                    if symbol.startswith('SHFE'):
                        if position.pos_short_today > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSETODAY",
                                volume=position.pos_short_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今空仓(均线追踪止损): 手数: {position.pos_short_today}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}今空仓(均线追踪止损): 手数: {position.pos_short_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_short_his > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSE",
                                volume=position.pos_short_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨空仓(均线追踪止损): 手数: {position.pos_short_his}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}昨空仓(均线追踪止损): 手数: {position.pos_short_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        limit_price = quote.ask_price1 + 2 * quote.price_tick
                        if position.pos_short > 0:
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSE",
                                volume=position.pos_short,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平{symbol}空仓(均线追踪止损): 手数: {position.pos_short}",
                                style="trade"
                            )
                            logging.info(
                                f"平{symbol}空仓(均线追踪止损): 手数: {position.pos_short}, 平仓价格: {limit_price}"
                            )


                # 处理多单
                if trading_line[-2] < short_line[-2]:
                    if symbol.startswith('SHFE'):
                        if position.pos_long_today > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSETODAY",
                                volume=position.pos_long_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今多仓(均线追踪止损): 手数: {position.pos_long_today}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}今多仓(均线追踪止损): 手数: {position.pos_long_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_long_his > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSE",
                                volume=position.pos_long_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨多仓(均线追踪止损): 手数: {position.pos_long_his}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}昨多仓(均线追踪止损): 手数: {position.pos_long_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        if position.pos_long>0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSE",
                                volume=position.pos_long,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平{symbol}多仓(均线追踪止损): 手数: {position.pos_long}",
                                style="trade"
                            )
                            logging.info(
                                f"平{symbol}多仓(均线追踪止损): 手数: {position.pos_long}, 平仓价格: {limit_price}"
                            )


                #****************************************开仓**************************************************
                # 获取所有配置项
                configs = get_all_configs()
                open_auto = configs.get('open_auto', 'off').lower() == 'on'
                if  open_auto:
                    # 检查是否需要开多仓
                    if position.pos_long==0 and (dks == "只做多" or dks == "双向") and trading_line[-2] > short_line[-2] and  trading_line[-3] < short_line[-3] :
                        # 对上海交易所的商品开多仓
                        if symbol.startswith('SHFE'):
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            #if position.pos_long_today == 0 and position.pos_long_his==0 and position.pos_long==0:
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="OPEN",
                                volume=1,  # 开仓手数，可根据需求调整
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 开SHFE{symbol}多仓: 手数: 1",
                                style="trade"
                            )
                            logging.info(
                                f"开SHFE{symbol}多仓: 手数: 1, 开仓价格: {limit_price}"
                            )
                        # 非上海交易所的商品开多仓
                        else:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            #if position.pos_long==0:
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="OPEN",
                                volume=1,  # 开仓手数，可根据需求调整
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 开{symbol}多仓: 手数: 1",
                                style="trade"
                            )
                            logging.info(
                                f"开{symbol}多仓: 手数: 1, 开仓价格: {limit_price}"
                            )
                    # 检查是否需要开空仓
                    if  position.pos_short==0 and (dks == "只做空" or dks == "双向") and trading_line[-2] < short_line[-2] and trading_line[-3] > short_line[-3]:
                        # 对上海交易所的商品开空仓
                        if symbol.startswith('SHFE'):
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            #if position.pos_short_today == 0 and position.pos_short_his==0 and position.pos_short==0:
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="OPEN",
                                volume=1,  # 开仓手数，可根据需求调整
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 开SHFE{symbol}空仓: 手数: 1",
                                style="trade"
                            )
                            logging.info(
                                f"开SHFE{symbol}空仓: 手数: 1, 开仓价格: {limit_price}"
                            )
                        # 非上海交易所的商品开空仓
                        else:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            #if position.pos_short==0:
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="OPEN",
                                volume=1,  # 开仓手数，可根据需求调整
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 开{symbol}空仓: 手数: 1",
                                style="trade"
                            )
                            logging.info(
                                f"开{symbol}空仓: 手数: 1, 开仓价格: {limit_price}"
                            )
                else:
                    console.print(f"{time.strftime('%X')} 自动开仓功能已关闭，跳过开仓检查", style="warning")

        except Exception as e:
            console.print(f"处理 {symbol} 止损逻辑时出错: {e}", style="error")
            # 移除错误日志记录


if __name__ == "__main__":
    try:
        api = TqApi(account=TqKq(), auth=TqAuth("cps168", "alibaba"))
        # 获取待监控的品种
        symbol_mtp_list = get_symbols()
        while True:
            deadline = time.time() + 2
            api.wait_update(deadline=deadline)
            console.print(f"**********{time.strftime('%X')} **********", style="warning")
            for symbol in symbol_mtp_list:
                stop_loss(symbol)
            time.sleep(0.2)

    except KeyboardInterrupt:
        pass
    finally:
        api.close()
        console.print("程序已停止", style="info")